package JUC.volatileDemo;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 高并发：多个线程访问同一个字节
 * <p>
 * 并行：多个事情同时去做
 * @author CKC
 */
public class VolatileDemo {
    
    public static void main(String[] args) {
        MyData myData = new MyData();
        for (int i = 0; i < 20; i++) {
            new Thread(() -> {
                for (int j = 1; j <= 1000; j++) {
                    myData.addPulsPuls();
                    myData.addMyAtomic();
                }
            }, String.valueOf(1)).start();
        }
        //需要等待上面20个线程都全部计算完成后，再用main线程取得最终的结果值看是多少?
        while (Thread.activeCount() > 2) {
            Thread.yield();
        }
        System.out.println(Thread.currentThread().getName() + "\t int type, finally  number value :" + myData.number);
        System.out.println(Thread.currentThread().getName() + "\t AtomicInteger type,finally  number value :" + myData.atomicInteger);
    }
    
    /**
     *
     * 1.可Volatile的见性验证<p>
     *   1.1 假如 int number = 0;   number变量之前根本没有添加volatile关键字修饰<p>
     *   1.2 添加了volatile ,可以解决可见性问题<p>
     *<p>
     * volatile 可以保证可见性，及时通知其他线程，主物理内存值已经被修改
     */
    private static void seeOkByVolatile() {
        MyData myData = new MyData();
        new Thread(() -> {
            System.out.println(Thread.currentThread().getName() + "\t  come in");
            //暂停一会儿线程
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            myData.addT060();
            System.out.println(Thread.currentThread().getName() + "\t  updated number value:" + myData.number);
        }, "AAA").start();
        //第二个线程是就是我们的main线程
        while (myData.number == 0) {
            //main线程就一直在这里等待循环，直到number值不再等于零
        }
        System.out.println(Thread.currentThread().getName() + "\t  mission is over,main get number value:" + myData.number);
    }
}

class MyData {
//    int number = 0;
    
    volatile int number = 0;
    
    public void addT060() {
        this.number = 60;
    }
    
    /**
     *  * 2.验证volatile不保证原子性<p>
     *  *    2.1 原子性指的是什么意思？<p>
     *  *         不可分割，完整性，也即某个线程正在做某一个具体业务时，中间不可以被加塞或者被分割。需要整体完整<p>
     *  *         要么同时成功，要么同时失败<p>
     *  *    2.2 volatile不保证原子性  案例演示<p>
     *  *    2.3   why<p>
     *  *    2.4如何解决原子性？<p>
     *  *          * 加synchronized<p>
     *  *          * 直接使用JUC下的AtomicInteger<p>
     *
     *
     * 请注意，此时number前面是加了volatile关键字修饰的，volatile不保证原子性(复合操作）
     */
    public void addPulsPuls() {
        number++;
    }
    
    AtomicInteger atomicInteger=new AtomicInteger();
    
    public void addMyAtomic(){
        atomicInteger.getAndIncrement();
    }
}